#include "./adsorb.hpp"

#include <qlib/all.h>
#include "../editing/editing.hpp"
#include "../layout/layout.hpp"
#include "../render/render.hpp"
#include "../select/select.hpp"
#include "../select/select_cmd.hpp"

/* For geometry operations */
#include <geos/geom/Coordinate.h>
#include <geos/geom/Envelope.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Point.h>

// /* For indexing */
#include <geos/index/strtree/TemplateSTRtree.h>

// /* For WKT read/write */
#include <geos/io/WKTReader.h>
#include <geos/io/WKTWriter.h>

namespace qbe::adsorb {
bool projectPointToSegment(const qlib::Vec2d& A, const qlib::Vec2d& B, const qlib::Vec2d& P, qlib::Vec2d& Q) {
  qlib::Vec2d AB = {B.x - A.x, B.y - A.y};  // 向量 AB
  qlib::Vec2d AP = {P.x - A.x, P.y - A.y};  // 向量 AP

  // 计算点积和向量 AB 的模长平方
  double dotProduct = AB.x * AP.x + AB.y * AP.y;
  double squaredLengthAB = AB.x * AB.x + AB.y * AB.y;

  // 计算投影系数 t
  double t = dotProduct / squaredLengthAB;

  // 如果 t 在 [0, 1] 之间，则投影点在线段上
  if (t >= 0 && t <= 1) {
    Q = {A.x + t * AB.x, A.y + t * AB.y};
    return true;
  }
  return false;
}

void adsorb_init(ecs::Commands commands, entt::registry& reg, ecs::Query query) {
  auto& render_model = query.get_resource<render::Model>();
  auto& model = query.get_resource<AdsorbModel>();

  auto gen_point_node = [&](auto& node, auto primitive, auto& color, int point_type = 0, float point_size = 10) {
    layout::renders::KeyPointUniform uniform;
    uniform.color = color;
    uniform.point_type = point_type;
    uniform.point_size = point_size;
    auto material =
        layout::renders::KeyPointShaderMaterial(uniform, "shaders/cell/layout-key-point.vert.spv", "shaders/cell/layout-key-point.frag.spv");
    node = layout::renders::PointMeshNode::create(render_model.options, layout::renders::Mesh(1), material, primitive);
    node->mesh.vertices->at(0) = vsg::vec2(10e9, 10e9);
    node->mesh.vertices->dirty();
    render_model.select_group->addChild(node);
  };

  gen_point_node(model.render_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, vsg::vec4(0.0, 1.0, 0.0, 1.0));

  // auto vertices = vsg::vec2Array::create(1);
  // (*vertices)[0] = vsg::vec2(10e9, 10e9);
  // vertices->properties.dataVariance = vsg::DYNAMIC_DATA;

  // render::Mesh2D mesh(vertices);
  // render::ShaderMaterial2D material{render::Uniform{
  //                                       vsg::vec3(0.0, 1.0, 0.0),
  //                                       vsg::vec3(0.0, 1.0, 0.0),
  //                                   },
  //                                   "shaders/cell/point.vert.spv", "shaders/cell/point.frag.spv"};
  // auto node = render::MeshNode::create(render_model.options, mesh, material, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
  // model.render_node = node;

  // render_model.scene->addChild(node);
}

void adsorb_diagonal(entt::registry& reg, ecs::Commands commands, ecs::Query query) {
  auto& state = query.get_resource<state::State>();
  auto& model = query.get_resource<AdsorbModel>();
  auto& axis = query.get_resource<axis::Axis>();
  auto& handle = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();

  // 斜角吸附
  if (!state.isAngleTheAdsorption()) {
    return;
  }

  auto snapToDiagonal = [](qlib::Vec2d& startPoint, qlib::Vec2d& endPoint) -> qlib::Vec2d {
    double dx = endPoint.x - startPoint.x;
    double dy = endPoint.y - startPoint.y;

    // 计算斜率和角度
    double angle = std::atan2(dy, dx) * 180 / M_PI;
    // 找到最接近的 45°倍数的角度
    int snappedAngle = static_cast<int>(std::round(angle / 45)) * 45;
    // 计算距离
    double distance = std::sqrt(dx * dx + dy * dy);

    // 根据最接近的 45°倍数的角度和距离计算新的终点
    double radians = snappedAngle * M_PI / 180;

    auto x = startPoint.x + static_cast<double>(distance * std::cos(radians));
    auto y = startPoint.y + static_cast<double>(distance * std::sin(radians));
    return qlib::Vec2d{x, y};
  };

  // // 记录斜角吸附起点的位置
  // if (handle->mouse_press) {
  //   model.mouse_press = true;
  //   // if (!model.exist) {
  //   //   model.diagonal_start_point = model.point;
  //   // } else {
  //   model.diagonal_start_point.x = axis.real_x;
  //   model.diagonal_start_point.y = axis.real_y;
  //   // }
  // }

  if (handle->mouse_move) {
    // 顶点吸附优先级高于斜角吸附
    if (!model.exist) {
      if (model.diagonal_enable) {
        auto p = snapToDiagonal(model.diagonal_start_point, qlib::Vec2d{axis.real_x, axis.real_y});
        auto grid_p = axis.getGridAdsorpPoint(p.x, p.y);
        axis.real_x = grid_p.x;
        axis.real_y = grid_p.y;
        model.point = qlib::Vec2d{grid_p.x, grid_p.y};
        SPDLOG_INFO("diagonal adsorb:( {}, {} )", p.x, p.y);
      }
    } else {
      SPDLOG_INFO("point adsorb");
    }
  }
}

void adsorb_vert(entt::registry& reg, ecs::Commands commands, ecs::Query query) {

  auto& state = query.get_resource<state::State>();

  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto& select_cmd = query.get_resource<select::SelectCmd>();
  auto& handle = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& axis = query.get_resource<axis::Axis>();
  auto& model = query.get_resource<AdsorbModel>();

  if (!state.isAdsorption()) {
    return;
  }

  auto absorb_range = 25;  // 像素

  if (handle->mouse_move) {

    auto& x = axis.real_x;
    auto& y = axis.real_y;

    model.exist = false;
    model.point = qlib::Vec2d{x, y};

    qlib::Vec2d p;
    auto is_find = select_cmd.get_adsorb(x, y, p, model.type);
    if (is_find) {
      SPDLOG_INFO("adsorb p: ({},{})", p.x, p.y);
      auto grid_p = axis.getGridAdsorpPoint(p.x, p.y);
      axis.real_x = grid_p.x;
      axis.real_y = grid_p.y;
      model.point = qlib::Vec2d{grid_p.x, grid_p.y};
      model.exist = true;
    }

    // 启用渲染
    if (model.exist) {
      // 修改坐标点为吸附点
      // axis.real_x = model.point.x;
      // axis.real_y = model.point.y;
      model.render_update = true;
    } else {
      model.render_clear = true;
    }
  }
}

void adsorb_render(entt::registry& reg, ecs::Query query) {
  auto& render_model = query.get_resource<render::Model>();
  auto& model = query.get_resource<AdsorbModel>();

  auto& state = query.get_resource<state::State>();
  auto& axis = query.get_resource<axis::Axis>();

  if (!state.isAdsorption()) {
    model.render_clear = true;
  }

  if (model.render_update) {
    model.render_update = false;

    model.render_node->material.set_type(7);
    if (model.type == qlib::GeoPartType::Point) {
      model.render_node->material.set_type(5);
    }

    if (model.type == qlib::GeoPartType::Edge) {
      model.render_node->material.set_type(1);
    }

    if (model.type == qlib::GeoPartType::EdgeMid) {
      model.render_node->material.set_type(4);
    }

    if (model.type == qlib::GeoPartType::Center) {
      model.render_node->material.set_type(2);
    }

    model.render_node->mesh.vertices->at(0) = vsg::vec2(axis.real_x, axis.real_y);
    model.render_node->mesh.vertices->dirty();
    // layout::renders::Mesh mesh(1);
    // mesh.vertices->at(0) = vsg::vec2(axis.real_x, axis.real_y);
    // mesh.indices->at(0) = 0;
    // model.render_node->clear();
    // model.render_node->addMesh(mesh);
  }

  if (model.render_clear) {
    model.render_clear = false;
    model.render_node->mesh.vertices->at(0) = vsg::vec2(10e9, 10e9);
    model.render_node->mesh.vertices->dirty();
    // model.render_node->clear();
  }
}

void adsorb_filter_select(entt::registry& reg, ecs::Query query) {
  auto& model = query.get_resource<AdsorbModel>();
  // 过滤选择
  // auto& move_events = query.get_event_reader<move::Event>();
  // auto& affix_events = query.get_event_reader<affix::Event>();
  // // model.filter_select = false;
  // for (auto& e : move_events) {
  //   if (e.code == move::Code::Begin) {
  //     model.filter_select = true;
  //   }
  //   if (e.code == move::Code::End) {
  //     model.filter_select = false;
  //   }
  // }
  // for (auto& e : affix_events) {
  //   if (e.code == affix::Code::Begin) {
  //     model.filter_select = true;
  //   }
  //   if (e.code == affix::Code::End) {
  //     model.filter_select = false;
  //   }
  // }
}

void AdsorbPlugin::build(ecs::App& app) {
  app.init_resource<AdsorbModel>(AdsorbModel{});

  app.add_systems<ecs::stage::Startup>(adsorb_init);
  app.add_systems<ecs::stage::PreUpdate>(adsorb_vert, adsorb_diagonal);
  app.add_systems<ecs::stage::PostUpdate>(adsorb_render);
  app.add_systems<ecs::stage::PostUpdate>(adsorb_filter_select);
};

}  // namespace qbe::adsorb